package com.eastfair.questionnaire.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.eastfair.enums.SystemSourceEnum;
import com.eastfair.questionnaire.dto.ExternalAnswerDTO;
import com.eastfair.questionnaire.dto.InternalAnswerDTO;
import com.eastfair.questionnaire.enums.QuestionnaireRelationTypeEnum;
import com.eastfair.questionnaire.service.AnswerService;
import com.eastfair.questionnaire.service.QuestionnaireRelationService;
import com.eastfair.questionnaire.service.RelationExternalAnswerService;
import com.eastfair.questionnaire.vo.AnswerVO;
import com.eastfair.questionnaire.vo.ExternalAnswerVO;
import com.eastfair.questionnaire.vo.InternalAnswerVO;
import com.eastfair.questionnaire.vo.QuestionnaireRelationVO;
import com.google.common.collect.Lists;
import javafx.util.Pair;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @ClassName RelationExternalAnswerServiceImpl
 * @Description TODO
 * @Author yuwx
 * @Date 2021/8/28 13:44
 * @Version 1.0
 **/
@Slf4j
@Service
public class RelationExternalAnswerServiceImpl implements RelationExternalAnswerService {
    private QuestionnaireRelationService questionnaireRelationService;
    private AnswerService answerService;

    @Autowired
    public RelationExternalAnswerServiceImpl(QuestionnaireRelationService questionnaireRelationService, AnswerService answerService) {
        this.questionnaireRelationService = questionnaireRelationService;
        this.answerService = answerService;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveQuestion(Long projectId, SystemSourceEnum systemSourceEnum, Pair<Long, String> relation) {
        if (Objects.isNull(projectId)
                || Objects.isNull(systemSourceEnum)
                || Objects.isNull(relation)
                || Objects.isNull(relation.getKey())) {
            throw new NullPointerException("params is null");
        }
        QuestionnaireRelationTypeEnum relationTypeEnum = QuestionnaireRelationTypeEnum.QUESTION_QUESTION;
        questionnaireRelationService.save(projectId, relationTypeEnum, systemSourceEnum, Lists.newArrayList(relation));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveAnswer(Long projectId, SystemSourceEnum systemSourceEnum, Pair<Long, String> relation) {
        if (Objects.isNull(projectId)
                || Objects.isNull(systemSourceEnum)
                || Objects.isNull(relation)
                || Objects.isNull(relation.getKey())) {
            throw new NullPointerException("params is null");
        }
        QuestionnaireRelationTypeEnum relationTypeEnum = QuestionnaireRelationTypeEnum.ANSWER_ANSWER;
        questionnaireRelationService.save(projectId, relationTypeEnum, systemSourceEnum, Lists.newArrayList(relation));
    }

    @Override
    public Map<String, List<ExternalAnswerVO>> convertInternalToExternal(Long projectId, SystemSourceEnum systemSourceEnum, List<InternalAnswerDTO> internalAnswerList) {
        if (Objects.isNull(projectId)
                || Objects.isNull(systemSourceEnum)) {
            throw new NullPointerException("params is null");
        }
        if (CollectionUtil.isEmpty(internalAnswerList)) {
            return Collections.emptyMap();
        }
        List<Long> internalAnswerIdList = internalAnswerList.stream().map(InternalAnswerDTO::getInternalAnswerId).collect(Collectors.toList());
        Map<Long, List<AnswerVO>> questionMap = answerService.groupByQuestionId(projectId, internalAnswerIdList);
        Map<Long, List<Long>> questionIdMap = new HashMap<>();
        for (Map.Entry<Long, List<AnswerVO>> question : questionMap.entrySet()) {
            questionIdMap.put(question.getKey(), question.getValue().stream().map(AnswerVO::getId).collect(Collectors.toList()));
        }
        List<Long> questionIdList = questionMap.keySet().stream().collect(Collectors.toList());

        List<QuestionnaireRelationVO> questionRelationList = questionnaireRelationService.listByInternal(projectId, QuestionnaireRelationTypeEnum.QUESTION_QUESTION, systemSourceEnum, questionIdList);
        List<QuestionnaireRelationVO> answerRelationList = questionnaireRelationService.listByInternal(projectId, QuestionnaireRelationTypeEnum.ANSWER_ANSWER, systemSourceEnum, internalAnswerIdList);

        Map<Long, String> questionRelationMap = questionRelationList.stream().collect(Collectors.toMap(QuestionnaireRelationVO::getSelfId, QuestionnaireRelationVO::getExternalId));
        Map<Long, String> answerRelationMap = answerRelationList.stream().collect(Collectors.toMap(QuestionnaireRelationVO::getSelfId, QuestionnaireRelationVO::getExternalId));

        Map<String, List<ExternalAnswerVO>> convertQuestionMap = convertToRelation(questionIdMap, questionRelationMap, answerRelationMap,
                internalAnswerList.stream().collect(Collectors.toMap(InternalAnswerDTO::getInternalAnswerId, InternalAnswerDTO::getInputResult)));

        return convertQuestionMap;
    }

    @Override
    public Map<Long, List<InternalAnswerVO>> convertExternalToInternal(Long projectId, SystemSourceEnum systemSourceEnum, List<ExternalAnswerDTO> externalAnswerList) {
        if (Objects.isNull(projectId)
                || Objects.isNull(systemSourceEnum)) {
            throw new NullPointerException("params is null");
        }
        if (CollectionUtil.isEmpty(externalAnswerList)) {
            return Collections.emptyMap();
        }
        List<QuestionnaireRelationVO> answerRelationList = questionnaireRelationService.listByExternal(projectId, QuestionnaireRelationTypeEnum.ANSWER_ANSWER, systemSourceEnum, externalAnswerList.stream().map(ExternalAnswerDTO::getExternalAnswerId).collect(Collectors.toList()));
        List<Long> internalAnswerIdList = answerRelationList.stream().map(QuestionnaireRelationVO::getSelfId).collect(Collectors.toList());
        Map<Long, List<AnswerVO>> questionMap = answerService.groupByQuestionId(projectId, internalAnswerIdList);
        return convertAnswerToInternalAnswerVO(questionMap, externalAnswerList, answerRelationList);
    }

    /**
     * Description 转换answer为InternalAnswerVO，用于做后续转换
     *
     * @param questionMap
     * @param externalAnswerIdList
     * @param answerRelationList
     * @return java.util.Map<java.lang.Long, java.util.List < com.eastfair.questionnaire.vo.InternalAnswerVO>>
     * @Date 13:52 2021/9/15
     * @Author yuwx
     **/
    private Map<Long, List<InternalAnswerVO>> convertAnswerToInternalAnswerVO(Map<Long, List<AnswerVO>> questionMap, List<ExternalAnswerDTO> externalAnswerIdList, List<QuestionnaireRelationVO> answerRelationList) {
        final Map<Long, String> relationMap = answerRelationList.stream().collect(Collectors.toMap(QuestionnaireRelationVO::getSelfId, QuestionnaireRelationVO::getExternalId));
        final Map<String, String> answerResultMap = externalAnswerIdList.stream().collect(Collectors.toMap(ExternalAnswerDTO::getExternalAnswerId, ExternalAnswerDTO::getInputResult));
        Map<Long, List<InternalAnswerVO>> internalAnswerMap = new HashMap<>();
        for (Map.Entry<Long, List<AnswerVO>> entity : questionMap.entrySet()) {
            internalAnswerMap.put(entity.getKey(), entity.getValue().stream().map(answerVO ->
                    InternalAnswerVO.builder().internalAnswerId(answerVO.getId()).inputResult(answerResultMap.get(relationMap.get(answerVO.getId()))).build()
            ).collect(Collectors.toList()));
        }
        return internalAnswerMap;
    }

    /**
     * Description 转换函数，将问题、答案结构，映射为其他系统id
     *
     * @param questionMap         问题原结构
     * @param questionRelationMap 问题映射 T 转换源类型 R转换结果类型
     * @param answerRelationMap   答案映射
     * @return java.util.Map<R, java.util.List < R>>
     * @Date 9:48 2021/8/30
     * @Author yuwx
     **/
    private Map<String, List<ExternalAnswerVO>> convertToRelation(Map<Long, List<Long>> questionMap, Map<Long, String> questionRelationMap, Map<Long, String> answerRelationMap, Map<Long, String> answerInputResultMap) {

        Map<String, List<ExternalAnswerVO>> convertQuestionMap = new HashMap<>();
        for (Map.Entry<Long, List<Long>> questionAnswer : questionMap.entrySet()) {
            String relationQuestionId = questionRelationMap.get(questionAnswer.getKey());
            if (Objects.isNull(relationQuestionId)) {
                continue;
            }
            List<ExternalAnswerVO> relationAnswerList = convertQuestionMap.getOrDefault(relationQuestionId, new ArrayList<>());
            questionAnswer.getValue().stream().forEach(answerId -> {
                String relationAnswerId = answerRelationMap.get(answerId);
                if (!Objects.isNull(relationAnswerId)) {
                    relationAnswerList.add(ExternalAnswerVO.builder().externalAnswerId(relationAnswerId).inputResult(answerInputResultMap.get(answerId)).build());
                }
            });
            convertQuestionMap.put(relationQuestionId, relationAnswerList);
        }
        return convertQuestionMap;
    }
}
